﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;

namespace BBInterfaceNET.RuntimeTemplates
{
    public partial class FieldGenerationTemplate
    {
        public string SourceFilePath { get; set; }
        public string OutputPath { get; set; }

        private string GetCurrentElementName(XElement elem, Dictionary<string, int> typeIndex)
        {
            string typeName = UpperInitial(elem.Name.LocalName);
            string varName = null;
            var nm = elem.Attributes("Name").FirstOrDefault();
            if (nm != null)
            {
                varName = nm.Value;
            }
            else
            {
                if (!typeIndex.ContainsKey(typeName))
                    typeIndex.Add(typeName, 1);
                int val = typeIndex[typeName];
                varName = LowerInitial(typeName + val);
                typeIndex[typeName]++;
            }
            return varName;
        }

        private void WriteScreenInitialization(XElement doc)
        {
            Dictionary<string, int> typeIndex = new Dictionary<string, int>();
            var elems = doc.Elements().ToList();
            for (int i = 0; i < elems.Count; i++)
            {
                XElement el = elems[i];
                string name = el.Name.LocalName;
                WriteFieldInitialization("this", el, typeIndex);
            }
            //handle status, title, banner, font and bg
        }
        private string GetRootStyles(XElement elem)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));

            var vs = elem.Attributes("VerticalScroll").FirstOrDefault();
            if (vs != null && !(bool)vs)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.NO_VERTICAL_SCROLL");
            }
            var vsb = elem.Attributes("VerticalScrollBar").FirstOrDefault();
            if (vsb != null && !(bool)vsb)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.NO_VERTICAL_SCROLLBAR");
            }
            var hs = elem.Attributes("HorizontalScroll").FirstOrDefault();
            if (hs != null && (bool)hs)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.HORIZONTAL_SCROLL");
            }
            var hsb = elem.Attributes("HorizontalScrollBar").FirstOrDefault();
            if (hsb != null && (bool)hsb)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.HORIZONTAL_SCROLLBAR");
            }
            return style.ToString();
        }
        
        private void WriteFieldInitialization(string parentName, XElement elem, Dictionary<string, int> typeIndex)
        {
            //get the type
            string typeName = UpperInitial(elem.Name.LocalName);
            if(typeName=="Font")
            {
                ConstructFont(parentName, elem);
                return;
            }
            else if (typeName == "Background")
            {
                ConstructBackground(parentName, elem);
                return;
            }

            XElement childElem = elem;
            if (typeName == "Banner" || typeName == "Title" || typeName == "Status")
                childElem = elem.Elements().FirstOrDefault();

            //get the var name
            string varName = GetCurrentElementName(childElem, typeIndex);

            ConstructField(childElem, varName, UpperInitial(childElem.Name.LocalName));
            

            var qry = childElem.Elements().ToList();
            for (int i = 0; i < qry.Count; i++)
            {
                XElement el = qry[i];
                WriteFieldInitialization(varName, el, typeIndex);
            }
            string method = "add";
            if (typeName == "Banner")
                method = "setBanner";
            else if (typeName == "Title")
                method = "setTitle";
            else if (typeName == "Status")
                method = "setStatus";
            this.WriteLine(string.Format("{0}.{1}({2});\n", parentName, method, varName));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="elem">the font xml</param>
        /// <param name="varName">the name to which the font is added</param>
        private void ConstructFont(string varName, XElement elem)
        {
            string style = "Font.PLAIN";
            int sz = 0;
            var sAttr = elem.Attributes("Size").FirstOrDefault();
            if (sAttr != null)
                sz = (int)sAttr;
            sAttr = elem.Attributes("Style").FirstOrDefault();
            if (sAttr != null)
            {
                if (sAttr.Value == "Italic")
                    style = "Font.ITALIC";
                else if (sAttr.Value == "Bold")
                    style = "Font.BOLD";
                else if (sAttr.Value == "Underlined")
                    style = "Font.UNDERLINED";
            }
            string str = string.Format("{0}.setFont(Font.getDefault().derive({1}, {2}));", varName, style, sz);
            this.WriteLine(str);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="elem">the background xml</param>
        /// <param name="varName">the name to which the background is added</param>
        private void ConstructBackground(string varName, XElement elem)
        {
            string str = "";
            XElement bg = elem.Elements().FirstOrDefault();
            if (bg.Name.LocalName == "SolidColorBackground")
            {
                var val = bg.Attributes("Color").FirstOrDefault();
                string strVal = "";
                if (val != null) strVal = val.Value.Replace("#", "0x");
                str = string.Format("BackgroundFactory.createSolidBackground({0})", strVal);
            }
            else if (bg.Name.LocalName == "TransparentColorBackground")
            {
                var val = bg.Attributes("Color").FirstOrDefault();
                string strVal = "";
                if (val != null) strVal = val.Value.Replace("#", "0x");

                var a = bg.Attributes("Alpha").FirstOrDefault();
                int aVal = 255;
                if (a != null) aVal = (int)a;

                str = string.Format("BackgroundFactory.createSolidTransparentBackground({0}, {1})", strVal, aVal);
            }
            else if (bg.Name.LocalName == "LinearGradientBackground")
            {
                string c1 = "", c2 = "";
                var c1Attr = bg.Attributes("Color1").FirstOrDefault();
                if (c1Attr != null)
                {
                    c1 = c1Attr.Value.Replace("#", "0x");
                }
                var c2Attr = bg.Attributes("Color2").FirstOrDefault();
                if (c2Attr != null)
                {
                    c2 = c2Attr.Value.Replace("#", "0x");
                }

                int orientation = 0;//horiz
                var or = bg.Attributes("Orientation").FirstOrDefault();
                if (or != null && or.Value == "Vertical")
                    orientation = 1;
                if (orientation == 0)
                    str = string.Format("BackgroundFactory.createLinearGradientBackground({0}, {1}, {1}, {0})", c1, c2);
                else
                    str = string.Format("BackgroundFactory.createLinearGradientBackground({0}, {0}, {1}, {1})", c1, c2);
            }
            else
            {//image bg
                string path = "";
                var p = bg.Attributes("ImagePath").FirstOrDefault();
                if (p != null)
                    path = Path.GetFileName(p.Value);
                string r = "Background.REPREAT_SCALE_TO_FIT";
                var repeat = bg.Attributes("Repeat").FirstOrDefault();
                if (repeat != null)
                {
                    if (repeat.Value == "None")
                        r = "Background.REPEAT_NONE";
                    else if (repeat.Value == "Both")
                        r = "Background.REPEAT_BOTH";
                }
                string posX = "Background.POSITION_X_LEFT";
                var px = bg.Attributes("PosX").FirstOrDefault();
                if (px != null)
                {
                    if (px.Value == "Center")
                        posX = "Background.POSITION_X_CENTER";
                    else if (px.Value == "Right")
                        posX = "Background.POSITION_X_RIGHT";
                }
                string posY = "Background.POSITION_Y_TOP";
                var py = bg.Attributes("PosY").FirstOrDefault();
                if (py != null)
                {
                    if (py.Value == "Center")
                        posY = "Background.POSITION_Y_CENTER";
                    else if (py.Value == "Top")
                        posY = "Background.POSITION_Y_BOTTOM";
                }
                string bmp = string.Format("Bitmap.getBitmapResource(\"{0}\")", path);
                str = string.Format("BackgroundFactory.createBitmapBackground({0}, {1}, {2} ,{3})", bmp, posX, posY, r);
            }
            if (varName == "this") varName = "this.getMainManager()";
            this.WriteLine(string.Format("{0}.setBackground({1});", varName, str));
        }

        private void ConstructField(XElement elem, string varName, string typeName)
        {
            if (elem.Name.LocalName == "ButtonField")
            {
                ConstructButton(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "LabelField")
            {
                ConstructLabel(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "BitmapField")
            {
                ConstructBitmap(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "CheckboxField")
            {
                ConstructCheckbox(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "NumericChoiceField")
            {
                ConstructNumericChoice(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "EditField")
            {
                ConstructEditField(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "RadioButtonField")
            {
                ConstructRadio(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "VerticalFieldManager" ||
                elem.Name.LocalName == "HorizontalFieldManager" ||
                elem.Name.LocalName == "FlowFieldManager")
            {
                ConstructBasicManager(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "SeparatorField")
            {
                ConstructSeparator(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "GaugeField")
            {
                ConstructGaugeField(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "ObjectChoiceField")
            {
                ConstructObjectChoiceField(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "DateField")
            {
                ConstructDateField(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "RadioButtonField")
            {
                ConstructRadio(elem, varName, typeName);
            }
            else if (elem.Name.LocalName == "CustomListField")
            {
                ConstructCustomListField(elem, varName, typeName);
            }
            //set the margins
            var margins = elem.Attributes("Margin").FirstOrDefault();
            if (margins != null)
            {
                string[] m = margins.Value.Split(',');
                bool add = false;
                foreach(string s in m)
                    if (s.Trim() != "0") { add = true; break; }
                if (add)
                    this.WriteLine("{0}.setMargin({1});", varName, margins.Value);
            }
        }

        private void ConstructCustomListField(XElement elem, string varName, string typeName)
        {
            //generate the list items and the base custom list
            //than based on the listitem type instantiate an anonimous derived class or something
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));
            //list styles
            var ms = elem.Attributes("MultiSelect").FirstOrDefault();
            if (ms != null && (bool)ms)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("ListField.MULTI_SELECT");
            }
            var alt = elem.Attributes("NoAltedUpDown").FirstOrDefault();
            if (alt != null && (bool)alt)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("ListField.NO_ALTED_PAGE_UP_DOWN");
            }

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2});", varName, typeName, styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2});", varName, typeName, styleText));
            }
        }

        private void ConstructDateField(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));
            //add date field data
            string mode = "DateField.DATE_TIME";
            var modeAttr = elem.Attributes("Mode").FirstOrDefault();
            if (modeAttr != null)
            {
                if (modeAttr.Value == "Date")
                    mode = "DateField.DATE";
                else if (modeAttr.Value == "Time")
                    mode = "DateField.TIME";
            }
            if (mode != null)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append(mode);
            }
            string tFormat = null;
            var tfAttr = elem.Attributes("TimeFormat").FirstOrDefault();
            if (tfAttr != null)
            {
                if (tfAttr.Value == "Short")
                    tFormat = "DateFormat.TIME_SHORT";
                else if (tfAttr.Value == "Long")
                    tFormat = "DateFormat.TIME_LONG";
                else
                    tFormat = "DateFormat.TIME_DEFAULT";
            }
            string dFormat = null;
            var dfAttr = elem.Attributes("DateFormat").FirstOrDefault();
            if (dfAttr != null)
            {
                if (dfAttr.Value == "Short")
                    dFormat = "DateFormat.DATE_SHORT";
                else if (dfAttr.Value == "Long")
                    dFormat = "DateFormat.DATE_LONG";
                else if (dfAttr.Value == "Medium")
                    dFormat = "DateFormat.DATE_MEDIUM";
                else if (dfAttr.Value == "Full")
                    dFormat = "DateFormat.DATE_FULL";
                else
                    dFormat = "DateFormat.DATE_DEFAULT";
            }
            string format = "";
            if (tFormat != null)
                format += tFormat;
            if (dFormat != null)
            {
                if (format.Length > 0) format += " | ";
                format += dFormat;
            }
            //write DateFormat
            string dateFormat = string.Format("DateFormat.getInstance({0})", format);

            //write ctor
            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            //if (gen == null || (bool)gen)
            //{
            //    this.WriteLine(string.Format("{0} = new {1}(null, Long.MIN_VALUE, {2}{3}{4});", varName, typeName, "null", styleText.Length == 0 ? "" : ", ", styleText));
            //}
            //else
            //{
            //    this.WriteLine(string.Format("{1} {0} = new {1}(null, Long.MIN_VALUE, {2}{3}{4});", varName, typeName, "null", styleText.Length == 0 ? "" : ", ", styleText));
            //}
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}(null, Long.MIN_VALUE, {2});", varName, typeName, styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}(null, Long.MIN_VALUE, {2});", varName, typeName, styleText));
            }
            //set format

            this.WriteLine(string.Format("{0}.setFormat({1});", varName, dateFormat));
            //label
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value));
            //date
            var date = elem.Attributes("Date").FirstOrDefault();
            if (date != null)
                this.WriteLine(string.Format("{0}.setDate(HttpDateParser.parse(\"{1}\"));", varName, date.Value));
            //editable
            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null)
                this.WriteLine(string.Format("{0}.setEditable({1});", varName, editable.Value));

        }

        private void ConstructObjectChoiceField(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, null, 0, ", styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, null, 0, ", styleText));
            }

            //label
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value));
            //objects
            var choices = elem.Elements("Choice").ToList();
            if (choices.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < choices.Count - 1; i++)
                {
                    sb.Append(string.Format("\"{0}\", \r\n", choices[i].Attribute("Value").Value));
                }
                sb.Append(string.Format("\"{0}\"", choices[choices.Count - 1].Attribute("Value").Value));
                this.WriteLine(string.Format("Object[] choices=new Object[] {{ " + sb.ToString() + " }};"));

                this.WriteLine(string.Format("{0}.setChoices(choices);", varName));
            }

            //selected index
            var sel = elem.Attributes("SelectedIndex").FirstOrDefault();
            if (sel != null)
                this.WriteLine(string.Format("{0}.setSelectedIndex({1});", varName, sel.Value));

        }

        private void ConstructGaugeField(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));

            //get the gauge style bits
            var lblProgr = elem.Attributes("LabelAsProgress").FirstOrDefault();
            if (lblProgr != null && (bool)lblProgr)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("GaugeField.LABEL_AS_PROGRESS");
            }
            var noText = elem.Attributes("NoText").FirstOrDefault();
            if (noText != null && (bool)noText)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("GaugeField.NO_TEXT");
            }
            var percent = elem.Attributes("Percent").FirstOrDefault();
            if (percent != null && (bool)percent)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("GaugeField.PERCENT");
            }
            string styleText = style.ToString();

            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, 0, 100, 0, ", styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, 0, 100, 0, ", styleText));
            }

            //get the min, max, val and label
            string label = null;
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                label = lbl.Value;

            int min = 0;
            var mAttr = elem.Attributes("Minimum").FirstOrDefault();
            if (mAttr != null)
                min = (int)mAttr;
            int max = 100;
            mAttr = elem.Attributes("Maximum").FirstOrDefault();
            if (mAttr != null)
                max = (int)mAttr;
            int val = 0;
            mAttr = elem.Attributes("Value").FirstOrDefault();
            if (mAttr != null)
                val = (int)mAttr;

            this.WriteLine(string.Format("{0}.reset(\"{1}\", {2}, {3}, {4});", varName, label ?? "null", min, max, val));

            //editable is true by default
            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null)
                this.WriteLine(string.Format("{0}.setEditable({1});", varName, editable.Value));
        }

        private void ConstructSeparator(XElement elem, string varName, string typeName)
        {
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}();", varName, typeName));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}();", varName, typeName));
            }
        }

        private void ConstructBasicManager(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));
            //manager styles
            //v & h scrolling
            var vs = elem.Attributes("VerticalScroll").FirstOrDefault();
            if (typeName == "FlowFieldManager")
            {
                if (vs != null && !(bool)vs)
                {
                    if (style.Length > 0) style.Append(" | ");
                    style.Append("Manager.NO_VERTICAL_SCROLL");
                }
            }
            else
            {
                if (vs != null && (bool)vs)
                {
                    if (style.Length > 0) style.Append(" | ");
                    style.Append("Manager.VERTICAL_SCROLL");
                }
            }
            
            var hs = elem.Attributes("HorizontalScroll").FirstOrDefault();
            if (hs != null && (bool)hs)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.HORIZONTAL_SCROLL");
            }
            //v & h scroll bars
            var vsb = elem.Attributes("VerticalScrollBar").FirstOrDefault();
            if (vsb != null && (bool)vsb)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.VERTICAL_SCROLLBAR");
            }
            var hsb = elem.Attributes("HorizontalScrollBar").FirstOrDefault();
            if (hsb != null && (bool)hsb)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Manager.HORIZONTAL_SCROLLBAR");
            }

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2});", varName, typeName, styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2});", varName, typeName, styleText));
            }
        }
        
        //not used at this point
        private void ConstructBasicManager2(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));

            //manager styles

            //v & h scrolling
            var vs = elem.Attributes("VerticalScroll").FirstOrDefault();
            if (vs != null)
            {
                if (style.Length > 0) style.Append(" | ");
                if ((bool)vs)
                    style.Append("Manager.VERTICAL_SCROLL");
                else
                    style.Append("Manager.NO_VERTICAL_SCROLL");
            }
            var hs = elem.Attributes("HorizontalScroll").FirstOrDefault();
            if (hs != null)
            {
                if (style.Length > 0) style.Append(" | ");
                if ((bool)hs)
                    style.Append("Manager.HORIZONTAL_SCROLL");
                else
                    style.Append("Manager.NO_HORIZONTAL_SCROLL");
            }
            //v & h scroll bars
            var vsb = elem.Attributes("VerticalScrollBar").FirstOrDefault();
            if (vsb != null)
            {
                if (style.Length > 0) style.Append(" | ");
                if ((bool)vsb)
                    style.Append("Manager.VERTICAL_SCROLLBAR");
                else
                    style.Append("Manager.NO_VERTICAL_SCROLLBAR");
            }
            var hsb = elem.Attributes("HorizontalScrollBar").FirstOrDefault();
            if (hsb != null)
            {
                if (style.Length > 0) style.Append(" | ");
                if ((bool)hsb)
                    style.Append("Manager.HORIZONTAL_SCROLLBAR");
                else
                    style.Append("Manager.NO_HORIZONTAL_SCROLLBAR");
            }


            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2});", varName, typeName, styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2});", varName, typeName, styleText));
            }
        }

        private void ConstructLabel(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, ", style.ToString()));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, ", style.ToString()));
            }

            var lbl = elem.Attributes("Text").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setText(\"{1}\");", varName, lbl.Value.Trim()));
        }

        private void ConstructBitmap(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, false));

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, ", style.ToString()));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, ", style.ToString()));
            }
            //space
            int hspace = 0; int vspace = 0;
            var hs = elem.Attributes("HorizontalSpace").FirstOrDefault();
            if (hs != null)
                hspace = (int)hs;
            var vs = elem.Attributes("VerticalSpace").FirstOrDefault();
            if (vs != null)
                vspace = (int)vs;

            if (hspace > 0 || vspace > 0)
                this.WriteLine(string.Format("{0}.setSpace({1}, {2});", varName, hspace, vspace));
            //bitmap
            var bmp = elem.Attributes("Bitmap").FirstOrDefault();
            if (bmp != null && bmp.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setBitmap(Bitmap.getBitmapResource(\"{1}\"));", varName, Path.GetFileName(bmp.Value)));
        }

        private void ConstructButton(XElement elem, string varName, string typeName)
        {
            //get the focusable and alignment fields
            //focusable is true by default
            //top left alignment is default
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));
            //button specific
            bool consumeClick = false;
            var consume = elem.Attributes("ConsumeClick").FirstOrDefault();
            if (consume != null && (bool)consume)
                consumeClick = true;
            bool neverDirty = false;
            var never = elem.Attributes("NeverDirty").FirstOrDefault();
            if (never != null && (bool)never)
                neverDirty = true;

            if (neverDirty)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("ButtonField.NEVER_DIRTY");
            }
            if (consumeClick)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("ButtonField.CONSUME_CLICK");
            }


            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2});", varName, typeName, style.ToString()));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2});", varName, typeName, style.ToString()));
            }

            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value.Trim()));

            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null && (bool)editable)
                this.WriteLine(string.Format("{0}.setEditable({1});", varName, editable.Value));
        }

        private void ConstructCheckbox(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, false, ", style.ToString()));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2}{3});", varName, typeName, styleText.Length == 0 ? "" : "null, false, ", style.ToString()));
            }
            //label
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value.Trim()));
            var chk = elem.Attributes("Checked").FirstOrDefault();
            if (chk != null && (bool)chk)
                this.WriteLine(string.Format("{0}.setChecked(true);", varName));
            //editable is true by default
            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null && !(bool)editable)
                this.WriteLine(string.Format("{0}.setEditable(false);", varName, editable.Value));
        }

        private void ConstructRadio(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));
            //handle the group name (RadioButtonGroup)
            string groupName = "defaultGroup";
            var grName = elem.Attributes("GroupName").FirstOrDefault();
            if (grName != null && grName.Value.Trim().Length > 0)
                groupName = grName.Value;

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}(null, {2}, false{3}{4});", varName, typeName, groupName, styleText.Length == 0 ? "" : ", ", style.ToString()));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}(null, {2}, false{3}{4});", varName, typeName, groupName, styleText.Length == 0 ? "" : ", ", style.ToString()));
            }
            //label
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value.Trim()));
            var chk = elem.Attributes("Selected").FirstOrDefault();
            if (chk != null && (bool)chk)
                this.WriteLine(string.Format("{0}.setSelected(true);", varName));
            //editable is true by default
            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null && !(bool)editable)
                this.WriteLine(string.Format("{0}.setEditable(false);", varName, editable.Value));
        }

        private void ConstructNumericChoice(XElement elem, string varName, string typeName)
        {
            //there are no styles that can be set on a numeric choice field

            //start
            int start = 0;
            var startAttr = elem.Attributes("Start").FirstOrDefault();
            if (startAttr != null)
                start = (int)startAttr;
            //end
            int end = 0;
            var endAttr = elem.Attributes("End").FirstOrDefault();
            if (endAttr != null)
                end = (int)endAttr;
            if (end < start) end = start;
            //increment
            int incr = 1;
            var incrAttr = elem.Attributes("Increment").FirstOrDefault();
            if (incrAttr != null)
                incr = (int)incrAttr;

            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}(null, {2}, {3}, {4});", varName, typeName, start, end, incr));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}(null, {2}, {3}, {4});", varName, typeName, start, end, incr));
            }

            //label
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value.Trim()));
            //selected index
            var selIdx = elem.Attributes("SelectedIndex").FirstOrDefault();
            if (selIdx != null)
                this.WriteLine(string.Format("{0}.setSelectedIndex({1});", varName, (int)selIdx));
        }

        private void ConstructEditField(XElement elem, string varName, string typeName)
        {
            StringBuilder style = new StringBuilder();
            style.Append(GetBaseClassStyles(elem, true));
            //more edit field styles

            string styleText = style.ToString();
            var gen = elem.Attributes("GenerateMember").SingleOrDefault();
            if (gen == null || (bool)gen)
            {
                this.WriteLine(string.Format("{0} = new {1}({2});", varName, typeName, styleText));
            }
            else
            {
                this.WriteLine(string.Format("{1} {0} = new {1}({2});", varName, typeName, styleText));
            }
            var lbl = elem.Attributes("Label").FirstOrDefault();
            if (lbl != null && lbl.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setLabel(\"{1}\");", varName, lbl.Value.Trim()));
            var txt = elem.Attributes("Text").FirstOrDefault();
            if (txt != null && txt.Value.Trim().Length > 0)
                this.WriteLine(string.Format("{0}.setText(\"{1}\");", varName, txt.Value.Trim()));
            //editable is true by default
            var editable = elem.Attributes("Editable").FirstOrDefault();
            if (editable != null && !(bool)editable)
                this.WriteLine(string.Format("{0}.setEditable(false);", varName));
        }

        private string GetBaseClassStyles(XElement elem, bool defaultFocusable)
        {
            bool focusable = defaultFocusable;
            var fAttr = elem.Attributes("Focusable").FirstOrDefault();
            if (fAttr != null)
                focusable = (bool)fAttr;
            int hAlign = 0;
            var hAttr = elem.Attributes("HorizontalAlignment").FirstOrDefault();
            if (hAttr != null)
            {
                if (hAttr.Value == "Center")
                    hAlign = 1;
                else if (hAttr.Value == "Right")
                    hAlign = 2;
            }
            int vAlign = 0;
            var vAttr = elem.Attributes("VerticalAlignment").FirstOrDefault();
            if (vAttr != null)
            {
                if (vAttr.Value == "Center")
                    vAlign = 1;
                else if (vAttr.Value == "Bottom")
                    vAlign = 2;
            }

            StringBuilder style = new StringBuilder();
            //general styles
            if (!focusable && defaultFocusable)
                style.Append("Field.NON_FOCUSABLE");
            else if (focusable && !defaultFocusable)
                style.Append("Field.FOCUSABLE");
            if (hAlign > 0)
            {
                if (style.Length > 0) style.Append(" | ");
                if (hAlign == 1)
                    style.Append("Field.FIELD_HCENTER");
                else
                    style.Append("Field.FIELD_RIGHT");
            }
            if (vAlign > 0)
            {
                if (style.Length > 0) style.Append(" | ");
                if (vAlign == 1)
                    style.Append("Field.FIELD_VCENTER");
                else
                    style.Append("Field.FIELD_BOTTOM");
            }

            //use all width 
            var uaw = elem.Attributes("UseAllWidth").FirstOrDefault();
            if (uaw != null && (bool)uaw)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Field.USE_ALL_WIDTH");
            }
            //use all height
            var uah = elem.Attributes("UseAllHeight").FirstOrDefault();
            if (uah != null && (bool)uah)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Field.USE_ALL_HEIGHT");
            }
            //readonly
            var ro = elem.Attributes("ReadOnly").FirstOrDefault();
            if (ro != null && (bool)ro)
            {
                if (style.Length > 0) style.Append(" | ");
                style.Append("Field.READONLY");
            }

            return style.ToString();
        }

        private void WriteImports(XElement elem)
        {
            List<string> imports = new List<string>();
            imports.Add("import net.rim.device.api.ui.Field;");
            imports.Add("import net.rim.device.api.ui.Manager;");
            imports.Add("import net.rim.device.api.ui.container.*;");
            var elems = elem.Descendants().ToList();
            for (int i = 0; i < elems.Count; i++)
            {
                string name = elems[i].Name.LocalName;
                string import = "";
                if (name == "CustomListField")
                {
                    import = "import view.customComponents.CustomListField;";
                } 
                else if (name.EndsWith("Field"))
                {
                    import = "import net.rim.device.api.ui.component.*;";                
                }
                else if(name.EndsWith("Manager"))
                {
                    import = "import net.rim.device.api.ui.container.*;";
                }
                else if (name.EndsWith("Background"))
                {
                    import = "import net.rim.device.api.ui.decor.*;";
                }
                
                if (!imports.Contains(import))
                    imports.Add(import);
            }
            
            foreach (string str in imports)
                this.WriteLine(str);
        }
        
        private void WriteFields(XElement doc)
        {
            Dictionary<string, int> typeIndex = new Dictionary<string, int>();
            var elems = doc.Descendants().ToList();
            string[] col = new string[] { "Font", "Background", "Title", "Banner", "Status" }; 
            for (int i = 0; i < elems.Count; i++)
            {
                if (col.Contains(elems[i].Name.LocalName) ||elems[i].Name.LocalName.EndsWith("Background"))
                    continue;
                XElement el = elems[i];
                var gen = el.Attributes("GenerateMember").SingleOrDefault();
                if (gen == null || (bool)gen)
                {
                    //get access. default=private
                    string access = "private";
                    var aa = el.Attributes("Visibility").FirstOrDefault();
                    if (aa != null)
                    {
                        access = LowerInitial(aa.Value);
                    }
                    //get type name
                    string typeName = UpperInitial(el.Name.LocalName);
                    //get variable name
                    string varName = GetCurrentElementName(el, typeIndex);
                    //display
                    this.WriteLine(string.Format("{0} {1} {2};", access, typeName, varName));

                    if (typeName == "RadioButtonField")
                    {
                        if (!typeIndex.ContainsKey("defaultGroup"))
                        {
                            this.WriteLine(string.Format("private RadioButtonGroup {0} = new RadioButtonGroup();", "defaultGroup"));
                            typeIndex["defaultGroup"] = 1;
                        }
                        var radGr = el.Attributes("GroupName").FirstOrDefault();
                        if (radGr != null && radGr.Value.Trim().Length > 0 && !typeIndex.ContainsKey(radGr.Value))
                        {
                            this.WriteLine(string.Format("private RadioButtonGroup {0} = new RadioButtonGroup();", radGr.Value));
                        }
                    }
                }
            }
        }

        private string UpperInitial(string name)
        {
            return name[0].ToString().ToUpperInvariant() + name.Substring(1);
        }
        private string LowerInitial(string name)
        {
            return name[0].ToString().ToLowerInvariant() + name.Substring(1);
        }
    }
}
